`timescale 1ns / 1ps
// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module ngsx #(parameter BYTE_REGS = 1,                                     //to define the amount of byte registers that are received by this slave
              parameter RST_VALUE_RX = 0,
              parameter RST_VALUE_TX = 0,
              parameter TX_ENDIAN = 0)                                     //if == 0, bit 0 is Tx last, if == 1, bit 0 is transmitted first (GSX to PCH requires TX_ENDIAN = 1)
(
 //% active low reset signal (driven from internal FPGA logic)
    input                             iRst_n,
 //% 2M clock from internal logic to run rst condition timer
    input                             iClk_2M,
 //% serial clock (driven from SGPIO master)
    input                             iMClk,
 //% Load signal (driven from SGPIO master to capture serial data input in parallel register)
    input                             iLoad_n,
 //% Serial data input (driven from SGPIO master)
    input                             iSData,
 //% Parallel data from internal logic to master
    input [(BYTE_REGS*8)-1:0]         iPData,
 //% Serial data output to SGPIO master
    output                            oSData,
 //% Parallel data to internal registers (slave)
    output reg [(BYTE_REGS*8)-1:0]    oPData
);
      

// Internal Signals


   reg [(BYTE_REGS*8)-1:0] rSToPAcc;   //Serial to Parallel Accumulator (for serial data from SGPIO master). Goes to internal registers
   reg [(BYTE_REGS*8)-1:0] rPDataIn;   //parallel data input register (to latch data before serializing), goes to SGPIO master
   

   reg [17:0] rWDT = 18'b0;               //Wach Dog Timer register (to detect IDLE bus condition (iClk_2M & iLoad_n & iSData at HIGH value for 64msec)
   reg rstEvnt = 1'b0;                    //if rWDT reaches 64msec, rstEvent is asserted, causing a synch reset to the BUS


   wire conditionReset;                   //combinational to monitor for the IDLE bus condition (iClk_2M & iLoad_n & iSData at HIGH value). Serves as rWDT enable, otherwise, restart


//////////////////////////////////////////////////////////////////////////////////
// Sequential logic
//////////////////////////////////////////////////////////////////////////////////


always @(posedge iMClk, negedge iRst_n)
  begin
     if (!iRst_n)   //synchronous reset condition for outputs and internal signals
       begin
          rSToPAcc <= RST_VALUE_RX;
          oPData   <= RST_VALUE_RX;
          rPDataIn <= RST_VALUE_TX;
       end //if (!rst_n)

     else if (rstEvnt)
       begin
          rSToPAcc <= RST_VALUE_RX;
          oPData   <= RST_VALUE_RX;
          rPDataIn <= RST_VALUE_TX;
       end
     else
       begin
          //logic for serial data coming from SGPIO Master that goes to internal logic
          rSToPAcc = {rSToPAcc[(BYTE_REGS*8)-2:0], iSData};
          
          if (!iLoad_n)  //parallel data is captured to start serialization for data that goes to SGPIO Master
            begin
               rPDataIn <= iPData;    //parallel data is captured in shift register to be serialized when Load==0
               oPData = rSToPAcc;    //parallel output is driven when Load==0 
            end //if (!iLoad_n)
          else 
            begin
               if (TX_ENDIAN)
                 rPDataIn[BYTE_REGS*8 - 1:0] <= {1'b0, rPDataIn[BYTE_REGS*8 - 1 : 1]};   //shifting register to serialize parallel input (big endian)
               else
                 rPDataIn[BYTE_REGS*8 - 1:0] <= {rPDataIn[BYTE_REGS*8 - 2:0], 1'b0};   //shifting register to serialize parallel input (little endian)
               
            end //not(if (!iLoad_n))
          
       end // else: !if(!iRst_n)
  end // always @ (posedge iMClk, negedge iRst_n)
   



   
   //Sequencer for FSM
   always @(posedge iClk_2M, negedge iRst_n) begin //iclk 2MHz clk
      if (!iRst_n) begin
         rWDT <= 18'b0; // Initial state
         rstEvnt <= 1'b0;
      end
      else 
        begin
           if(conditionReset && (rWDT < 128000) && (!rstEvnt))
             begin
                rWDT <= rWDT + 18'b1; //Incrementing rWDT
             end
         else
           begin
              if (rWDT == 128000) //Counter to target 64ms using a ref clk of 2MHz
                begin
                   rstEvnt <= 1'b1; //Assert reset Event
                end
              if(!conditionReset) //If condition is not met, keep signal inactive
                begin
                   rstEvnt <= 1'b0;
                end
              rWDT <= 18'b0;
           end // else: !if(conditionReset && (rWDT < 128000) && (!rstEvnt))
        end // else: !if(!iRst_n)
   end // always @ (posedge iClk_2M, negedge iRst_n)
   


   //////////////////////////////////////////////////////////////////////////////////
   // Continous assigments
   //////////////////////////////////////////////////////////////////////////////////
   
   assign oSData = TX_ENDIAN ? rPDataIn[0] : rPDataIn[(BYTE_REGS*8) - 1];        //serial output is the MSb of the shifted register
      
   
   assign conditionReset = iMClk & iLoad_n & iSData; //conditions to start the counter.. Reset condition

   
endmodule //module NGSX
